package it.uniroma2.svd.writer;


import it.uniroma2.svd.DataInterface;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Hashtable;

import it.uniroma2.svd.writer.FileTools;
import it.uniroma2.svd.writer.LittleEndianInputStream;
import it.uniroma2.svd.writer.LittleEndianOutputStream;



public class FileToolsBinLE implements FileTools {
	
	LittleEndianOutputStream out = null;
	
	/**
	 * apre il canale di Output proprio dei metodi di scrittura binaria little Endian
	 * @param PathOutput
	 * @throws Exception
	 */

	public void initHandle  (String PathOutput) throws  Exception {
		
		out = new LittleEndianOutputStream(new FileOutputStream(PathOutput) );				

		
	}
	
	public void closeHandle () throws  Exception {
		
		out.flush();
		out.close();
		
	}

	

	/**
	 * 
	 * carica i dati nelle matrici LSA strutturandoli nei diversi campi leggendoli da file (formato Binary: Little Endian)
	 *
	 * @throws Exception
	 */
	
	public  Object[] loadToken (String PathInput)  throws  Exception {
		
			 Hashtable<String, Integer>dataHash = new Hashtable<String, Integer>();		
			 LittleEndianInputStream in = new LittleEndianInputStream(new FileInputStream(PathInput) );

	 		int row = in.readLEInt();
	 		int column = in.readLEInt();

			Object[][] data = new Object[row][4];

			for (int i = 0; i < row; i++) {
				
				short lungStr = in.readLEShort();
				String feature = in.readString(lungStr);
				data[i][0] = feature;
				data[i][1] = new Float(in.readLEFloat());
				data[i][2] = new Float(in.readLEFloat());

				
				float[] matrixData = new float[column];
				for (int j = 0; j < column; j++)  
					matrixData[j] = in.readLEFloat();
				data[i][3] = matrixData;
	
			
				dataHash.put(feature.trim(), new Integer (i));	// !!!  questa e' la Hashtable con cui cercare le parole nelle matrici

			}
			
			in.close();

			
		
		Object[] ritorni ={data, dataHash};	// array dei dati, hashtable chiavi
		return ritorni;
		
	}
		
			
//	
//	
//	/**
//	 * Scrive su File i vettori  LSA (formato Binary: Little Endian)
//	 *
//	 * 
//	 * @param matrixData  la matrice dei dati (index(doc o word), LSA vector) 
//	 * @param pathOut	il pathname dove scrivere il file 
//	 * @param reverse	HashMap<Integer, String>  (indexDoc, NameDoc) opp (indexWord, nameWord)
//	 * @param weight	BinaryMatrix<Float> descrittore del file delle pesature (null se matrixData e'
//	 * la matrice dei documenti)
//	 * @throws Exception
//	 */	
//	
//	public  void writeToken (float[][] matrixData, 
//			String pathOut, 
//			HashMap<Integer, String> reverse,
//			BinaryMatrix<Float>   weight)  throws  Exception {
//		
//		try {
//			
//
//			int row = matrixData.length;
//			int column = matrixData[0].length;
//			
//			 LittleEndianOutputStream out = new LittleEndianOutputStream(new FileOutputStream(pathOut) );
//			
//			// scrive in testa alla matrice il num_righe num_colonne
//	 		out.writeLEInt(row);
//	 		out.writeLEInt(column);
//
//		 	System.out.println("path Out writing in progress (One dot every 1000 lines): "+pathOut);
//
//
//			for (int index = 0; index < row; index++) {  
//								
//			 	String feature = reverse.get(index);
//			 	
//			 										//caso in cui non sono state calcolate le matrici di pesatura
//			 										// oppure scrive i documenti
//			 	if (weight == null) {				// formato lengWord+Word+0.0F+0.0F
//			 		out.writeLEShort((short)feature.length());
//			 		out.writeString(feature, feature.length());  
//			 		out.writeLEFloat(0.0F);
//			 		out.writeLEFloat(0.0F);
//			 	} else {							// formato lengWord+Word+weigth+0.0F
//			 		out.writeLEShort((short)feature.length());
//			 		out.writeString(feature, feature.length());  
//			 		out.writeLEFloat(FileToolsTxt.WeigthW(weight, index));
//			 		out.writeLEFloat(0.0F);
//			 	}
//
//			 	
//			 	for (int n = 0; n < column; n++) 	
//			 					out.writeLEFloat( matrixData[index][n] );		// formato float+float+...		
//			 	
//			 	if (index % 1000 == 0)
//			 		System.out.print(".");
//
//			 	
//			}
//			
//			out.close();
//			
//
//			
//		} catch ( Exception e ) {  
//			throw e;
//		} 
//	}
//	
//
//	
//	/**
//	 * Scrive su File i vettori  LSA (formato Binary)
//	 *
//	 * 
//	 * @param matrixData  la matrice dei dati (index(doc o word), LSA vector) 
//	 * @param pathOut	il pathname dove scrivere il file 
//	 * @param reverse	HashMap<Integer, String>  (indexDoc, NameDoc) opp (indexWord, nameWord)
//	 * @param WeightPath	il file delle pesature. Usato per i termini se BinaryMatrix<Float> e' troppo lento 
//	 * la matrice dei documenti) - Il file contiene su ogni riga il valore esatto del peso per il termine in corrispondenza della riga
//	 * @throws Exception
//	 */	
//	
//	public void writeToken (float[][] matrixData, 
//			String pathOut, 
//			HashMap<Integer, String> reverse,
//			String   WeightPath)  throws  Exception {
//		
//		try {
//			
//
//			int row = matrixData.length;
//			int column = matrixData[0].length;
//			
//			LittleEndianOutputStream out = new LittleEndianOutputStream(new FileOutputStream(pathOut) );				
//			ReadFileWeigth read = new ReadFileWeigth(WeightPath);
//			Vector <Float>weight = read.getWeight();
//
//			
//			// scrive in testa alla matrice il num_righe num_colonne
//	 		out.writeLEInt(row);
//	 		out.writeLEInt(column);
//	 		
//		 	System.out.println("path Out writing in progress (One dot every 1000 lines): "+pathOut);
//
//
//			for (int index = 0; index < row; index++) {  
//								
//			 	String feature = reverse.get(index);
//			 	
//			 										//caso in cui non sono state calcolate le matrici di pesatura
//			 										// oppure scrive i documenti
//			 	if (weight == null) {				// formato lengWord+Word+0.0F+0.0F
//			 		out.writeLEShort((short)feature.length());
//			 		out.writeString(feature, feature.length());  
//			 		out.writeLEFloat(0.0F);
//			 		out.writeLEFloat(0.0F);
//			 	} else {							// formato lengWord+Word+weigth+0.0F
//			 		out.writeLEShort((short)feature.length());
//			 		out.writeString(feature, feature.length());  
//			 		out.writeLEFloat(weight.elementAt(index));
//			 		out.writeLEFloat(0.0F);
//			 	}
//
//			 	
//			 	for (int n = 0; n < column; n++) 	
//			 					out.writeLEFloat( matrixData[index][n] );		// formato float+float+...		
//			 	
//			 	if (index % 1000 == 0)
//			 		System.out.print(".");
//
//			}
//			
//			out.close();
//			
//
//			
//		} catch ( Exception e ) {  
//			throw e;
//		} 
//	}
//	
	
	/**
	 * Scrive su File i vettori  LSA (formato Bin LE)
	 * 
	 * @param matrixData  la matrice dei dati ristretta al vettore corrisp a una linea (index(doc o word), LSA vector) 
	 * @param index l'indice riga
	 * @param data	HashMap<Integer, String>  (indexDoc, NameDoc) opp (indexWord, nameWord)
	 * @param output_ il printerWriter di scrittura 
	 * @param type DOC o WORD
	 * @throws Exception
	 */	


public void writeTokenLine(float[] matrixData, 
		int index,
		DataInterface data,
		FileTools.type type) throws Exception {
	
	int column = matrixData.length;
	int row = 0;
	String feature = null;
		Float weight;				


		try{
	
			
			switch (type) {
			case DOC:
				row = data.documentSize();
				feature = data.getDoc(index);
				break;
			case WORD:
				row = data.termSize();
				feature = data.getWord(index);
				break;
			default:
				break;
			}			
			
			// scrive in testa alla matrice il num_righe num_colonne
			if (index == 0) {
		 		out.writeLEInt(row);
		 		out.writeLEInt(column);
			}
			
			 	
			 	weight =((data.getWordWeight(index)!=null)?(new Float(data.getWordWeight(index))):0.0F);
			 	out.writeLEShort((short)feature.length());
		 		out.writeString(feature, feature.length());  
		 		out.writeLEFloat(weight);
		 		out.writeLEFloat(0.0F);

		 		
		 		for (int n = 0; n < column; n++) 	
 					out.writeLEFloat( matrixData[n] );
		 		
			 	if (index % 1000 == 0)
			 		System.out.print(".");

			
			
		} catch ( Exception e ) {  
			throw e;
		} 	
	}


public void writeToken(float[][] matrixData, String pathOutput,  DataInterface data,  FileTools.type type) throws Exception {  
	
	try {
		
		out = new LittleEndianOutputStream(new FileOutputStream(pathOutput) );				


		int row = matrixData.length;                 
		int column = matrixData[0].length;

		// scrive in testa alla matrice il num_righe num_colonne
 		out.writeLEInt(row);
 		out.writeLEInt(column);


		System.out.println("path Out writing in progress (One dot every 1000 lines): "+pathOutput); 
		Float weight;
		
		for (int index = 0; index < row; index++) {

			String feature = null;
			
			switch (type) {
			case DOC:
				feature = data.getDoc(index);
				break;
			case WORD:
				feature = data.getWord(index);
				break;

			default:
				break;
			}
		 	
		 	weight =((data.getWordWeight(index)!=null)?(new Float(data.getWordWeight(index))):0.0F);
		 	out.writeLEShort((short)feature.length());
	 		out.writeString(feature, feature.length());  
	 		out.writeLEFloat(weight);
	 		out.writeLEFloat(0.0F);

	 		
	 		for (int n = 0; n < column; n++) 	
					out.writeLEFloat( matrixData[index][n] );
	 		
			if (index % 1000 == 0)                                  
				System.out.print(".");                 
		
		}                                 
		
		out.close();
		
	} catch ( Exception e ) {  
		throw e;
	} 	
	
}




}


